﻿using System.Reflection;

namespace ApplicationFrame.Model.Extensions
{
    public static class ObjectExtension
    {
        private static readonly BindingFlags _bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

        //
        // 摘要:
        //     获取某字段值
        //
        // 参数:
        //   type:
        //     类型
        //
        //   obj:
        //     对象
        //
        //   fieldName:
        //     字段名
        public static object GetTypeFieldValue(this Type type, object obj, string fieldName)
        {
            return type.GetField(fieldName, _bindingFlags).GetValue(obj);
        }

        //
        // 摘要:
        //     获取某字段值
        //
        // 参数:
        //   obj:
        //     对象
        //
        //   fieldName:
        //     字段名
        public static object GetFieldValue(this object obj, string fieldName)
        {
            return obj.GetType().GetField(fieldName, _bindingFlags).GetValue(obj);
        }

        //
        // 摘要:
        //     获取某属性值
        //
        // 参数:
        //   obj:
        //     对象
        //
        //   propertyName:
        //     属性名
        public static object GetPropertyValue(this object obj, string propertyName)
        {
            PropertyInfo ultimateShadowingProperty = obj.GetType().GetUltimateShadowingProperty(propertyName, _bindingFlags);
            if (ultimateShadowingProperty != null)
            {
                return ultimateShadowingProperty.GetValue(obj);
            }

            return null;
        }

        //
        // 摘要:
        //     获取某字段值
        //
        // 参数:
        //   type:
        //     类型
        //
        //   obj:
        //     对象
        //
        //   propertyName:
        //     属性名
        public static object GetTypePropertyValue(this Type type, object obj, string propertyName)
        {
            PropertyInfo ultimateShadowingProperty = type.GetUltimateShadowingProperty(propertyName, _bindingFlags);
            if (ultimateShadowingProperty != null)
            {
                return ultimateShadowingProperty.GetValue(obj);
            }

            return null;
        }

        public static PropertyInfo GetObjectProperty(this object obj, string propertyName)
        {
            return obj.GetType().GetUltimateShadowingProperty(propertyName, _bindingFlags);
        }

        //
        // 摘要:
        //     类型X是否包含某个属性
        //
        // 参数:
        //   type:
        //
        //   propertyName:
        public static bool ContainPropertyName(this Type type, string propertyName)
        {
            return type.GetUltimateShadowingProperty(propertyName, _bindingFlags) != null;
        }

        public static Type GetGenericType0(this Type genericType, Type arg0Type)
        {
            return genericType.MakeGenericType(arg0Type);
        }

        public static Type GetGenericType1(this Type genericType, Type arg0Type, Type arg1Type)
        {
            return genericType.MakeGenericType(arg0Type, arg1Type);
        }

        public static PropertyInfo GetUltimateShadowingProperty(this Type type, string name)
        {
            return type.GetUltimateShadowingProperty(name, _bindingFlags);
        }

        //
        // 摘要:
        //     https://github.com/nunit/nunit/blob/111fc6b5550f33b4fceb6ac8693c5692e99a5747/src/NUnitFramework/framework/Internal/Reflect.cs
        //
        //
        // 参数:
        //   type:
        //
        //   name:
        //
        //   bindingFlags:
        public static PropertyInfo GetUltimateShadowingProperty(this Type type, string name, BindingFlags bindingFlags)
        {
            if ((bindingFlags & BindingFlags.DeclaredOnly) != 0)
            {
                return type.GetProperty(name, bindingFlags);
            }

            if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == (BindingFlags.Public | BindingFlags.NonPublic))
            {
                Type type2 = type;
                while (type2 != null)
                {
                    PropertyInfo property = type2.GetProperty(name, (bindingFlags | BindingFlags.DeclaredOnly) & ~BindingFlags.NonPublic);
                    if (property != null)
                    {
                        return property;
                    }

                    type2 = type2.GetTypeInfo().BaseType;
                }

                bindingFlags &= ~BindingFlags.Public;
            }

            Type type3 = type;
            while (type3 != null)
            {
                PropertyInfo property2 = type3.GetProperty(name, bindingFlags | BindingFlags.DeclaredOnly);
                if (property2 != null)
                {
                    return property2;
                }

                type3 = type3.GetTypeInfo().BaseType;
            }

            return null;
        }
    }
}
